package com.jie.component.mongo.util;

import org.springframework.data.mongodb.core.mapping.Field;
import org.springframework.util.StringUtils;

import java.io.Serializable;
import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;

@SuppressWarnings("unused")
public class MongoUtil {
    private static final Map<String, String> FIELD_MAPPING_CACHE = new ConcurrentHashMap<>();

    @FunctionalInterface
    public interface SFunction<T, R> extends Function<T, R>, Serializable {
    }

    public static <T, R> String getFieldName(SFunction<T, R> func) {
        try {
            Method method = func.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(true);
            SerializedLambda serializedLambda = (SerializedLambda) method.invoke(func);
            
            String getter = serializedLambda.getImplMethodName();
            String className = serializedLambda.getImplClass().replace('/', '.');
            
            String cacheKey = className + "#" + getter;
            return FIELD_MAPPING_CACHE.computeIfAbsent(cacheKey, k -> {
                String fieldName = "";
                if (getter.startsWith("get")) {
                    fieldName = getter.substring(3);
                } else if (getter.startsWith("is")) {
                    fieldName = getter.substring(2);
                }
                
                fieldName = StringUtils.uncapitalize(fieldName);
                
                try {
                    Class<?> clazz = Class.forName(className);
                    java.lang.reflect.Field field = clazz.getDeclaredField(fieldName);
                    Field annotation = field.getAnnotation(Field.class);
                    if (annotation != null && StringUtils.hasText(annotation.value())) {
                        return annotation.value();
                    }
                } catch (Exception e) {
                    // ignore
                }
                
                return fieldName;
            });
        } catch (Exception e) {
            // TODO: 统一异常处理
            throw new RuntimeException("获取字段名失败", e);
        }
    }
}